package com.lkx.iocproject.inject;

import android.util.Log;
import android.view.View;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class InjectUtil {

    private static InjectUtil injectUtil = new InjectUtil();

    private InjectUtil(){

    }

    public static InjectUtil getInjectUtil(){
        return injectUtil;
    }

    public void inject(Object context){
        injectLayout(context);
        injectView(context);
        injectEvent(context);
    }

    /**
     *  textView.setOnClickListener（new View.OnClickListener() {
     * //                              @Override
     * //                              public void onClick(View v) {
     * //
     * //                              }
     * //                          });
     * 事件三要素
     * 事件源：TextView
     * 事件：new View.OnClickListener()
     * 事件处理：onClick（）
     * @param context
     */
    private void injectEvent(Object context) {
        //1.获取需要注册事件的方法
        Class<?> aClass = context.getClass();
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
            if (declaredAnnotations!=null && declaredAnnotations.length>0){
                for (Annotation declaredAnnotation : declaredAnnotations) {
                    EventBase eventBase = declaredAnnotation.annotationType().getAnnotation(EventBase.class);
                    if (eventBase != null) {
                        String listenerMethodName = eventBase.listenerMethodName();
                        Class<?> listenerParamsType = eventBase.listenerParamsType();
                        String callbackMethodName = eventBase.callbackMethodName();
                        //2.获取到事件源设置事件监听
                        try {
                            //有注册事件注解的的方法
                            Method registerMethod = declaredAnnotation.getClass().getDeclaredMethod("ids");
                            int[] ids = (int[]) registerMethod.invoke(declaredAnnotation);
                            if (ids != null && ids.length>0) {
                                for (int id : ids) {
                                    if (id!=-1){
                                        Method findViewById = aClass.getMethod("findViewById", int.class);
                                        //事件源
                                        View view = (View) findViewById.invoke(context, id);
                                        if (view != null) {
                                            //设置事件监听的方法
                                            Method setListenerMethod = view.getClass().getMethod(listenerMethodName, listenerParamsType);
                                            //设置监听，由于要将处理事件的方法传递出去，使用动态代理完成
                                            EventInvocationHandler invocationHandler = new EventInvocationHandler(context,method);
                                            Object proxy = Proxy.newProxyInstance(listenerParamsType.getClass().getClassLoader(), new Class[]{listenerParamsType}, invocationHandler);
                                            setListenerMethod.invoke(view,proxy);
                                        }
                                    }
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            Log.d("lkx_debug","事件注入出错了e ="+e.getMessage());
                        }
                    }
                }
            }
        }
    }

    private void injectView(Object context) {
        Class<?> aClass = context.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            ViewInject annotation = declaredField.getAnnotation(ViewInject.class);
            if (annotation != null) {
                Method method = null;
                try {
                    method = aClass.getMethod("findViewById", int.class);
                    declaredField.setAccessible(true);
                    declaredField.set(context,method.invoke(context, annotation.value()));

                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    private void injectLayout(Object context) {
        Class<?> aClass = context.getClass();
        ContentView annotation = aClass.getAnnotation(ContentView.class);
        if (annotation != null) {
            try {
                Method method = aClass.getMethod("setContentView", int.class);
                method.invoke(context,annotation.value());
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

}
